import { _decorator, BoxCollider, CCInteger, Color, Component, Enum, GradientRange, ICollisionEvent, ITriggerEvent, Material, MeshColliderComponent, MeshRenderer, Node, ParticleSystem, RigidBody, tween, Vec3 } from 'cc';
import { GridController } from './GridController';
import ChessboardState from './ChessboardState';
import { color, GateDirection, ModelColor } from './enum';
import { Block } from './Block';
import { LBlockADsorptionEffect } from './LBlockADsorptionEffect';
const { ccclass, property, executeInEditMode } = _decorator;

@ccclass('Gate')
@executeInEditMode(true)
export class Gate extends Component {

    @property(Node)
    Visual: Node;

    @property([Material])
    material: Material[] = [];

    @property(GridController)
    gridController: GridController;

    @property({ type: CCInteger })
    _gateLength: number = 1;

    @property({
        type: CCInteger,
        range: [1, 6, 1],
        slide: true
    })
    set gateLength(value: number) {
        this._gateLength = value;
        this.upDateGateModel();
    }
    get gateLength() {
        return this._gateLength;
    }

    @property(BoxCollider)
    blockBoxCollider: BoxCollider;

    @property({ type: Enum(ModelColor) })
    _modelColor: ModelColor = ModelColor.BlUE;

    @property({ type: Enum(ModelColor) })
    get modelColor(): ModelColor {
        return this._modelColor;
    }

    set modelColor(value: ModelColor) {
        this._modelColor = value;
        this.updateModelColor()
        this.updateParticleColor();
    }

    @property({ type: GateDirection })
    _gateDirection: GateDirection;

    @property({ type: Enum(GateDirection) })
    get gateDirection() {
        return this._gateDirection;
    }

    set gateDirection(value: GateDirection) {
        this._gateDirection = value;
        this.updateGateDirection(this._gateDirection)
    }

    max1;
    max2
    start() {
        this.blockBoxCollider.on("onCollisionEnter", this.onCollisionEnter, this);
        this.blockBoxCollider.on("onCollisionStay", this.onCollisionStay, this);
        this.blockBoxCollider.on("onCollisionExit", this.onCollisionExit, this);
        const { max1, max2 } = this.calcMaxRang();
        this.max1 = max1
        this.max2 = max2
        console.log(this.max1, 'max1', this.gateDirection)
        console.log(this.max2, 'max2', this.gateDirection)
        this.updateModelColor()


        let boxColliders = this.node.getChildByPath('GridGate3').children.filter(node => {
            return node.name.includes('Collider')
        })
        console.log(boxColliders, 'boxColliders')
        boxColliders.forEach((boxCollider, index) => {
            boxCollider.getComponent(BoxCollider).on('onTriggerEnter', (event: ITriggerEvent) => { this.onTriggerEnter(event, index) })
            boxCollider.getComponent(BoxCollider).on('onTriggerExit', this.onTriggerExit)
        })
        this.updateParticleColor();
    }
    updateParticleColor() {
        let gateColor: Color;
        switch (this.modelColor) {
            case ModelColor.RED:
                gateColor = color.RED;
                break;
            case ModelColor.BlUE:
                gateColor = color.BLUE;
                break;
            default:
                break;
        }
        if (!gateColor) {
            return;
        }
        const gradientRange = new GradientRange();
        gradientRange.color = gateColor;
        this.node.getComponentsInChildren(ParticleSystem).forEach(comp => {
            comp.colorOverLifetimeModule.color = gradientRange;
        })
    }
    onTriggerEnter(event: ITriggerEvent, index: number) {
        console.log('碰撞体触发')
        let particleSystems = this.node.getComponentsInChildren(ParticleSystem);
        particleSystems[particleSystems.length - 1 - index].play();
    }
    onTriggerExit() {

    }
    //改变模型颜色
    updateModelColor() {
        if (this.modelColor == ModelColor.RED) {
            this.Visual.getComponent(MeshRenderer).material = this.material[0];
        } else if (this.modelColor == ModelColor.BlUE) {
            this.Visual.getComponent(MeshRenderer).material = this.material[1];
        }
    }

    onCollisionEnter() {

    }
    onCollisionStay(event: ICollisionEvent) {
        console.log(event, 'onCollisionStay')
        let otherNode = event['otherCollider'].node;
        let rowAndColData = ChessboardState.findPosByvalue(otherNode.name).map(item => {
            if (this.gateDirection == GateDirection.TOP || this.gateDirection == GateDirection.Bottom) {
                return item.row;
            } else {
                return item.col;
            }

        })
        let rowAndColMax = Math.max(...rowAndColData);
        let rowAndColMin = Math.min(...rowAndColData);
        console.log(rowAndColMax, rowAndColMin, 'rowAndColMax,rowAndColMin');
        // console.log(this.max1,)
        let rangeLengthOK = false;

        if (this.gateDirection == GateDirection.TOP || this.gateDirection == GateDirection.Bottom) {
            if (this.max1.x <= rowAndColMin && this.max2.x >= rowAndColMax) {
                console.log('范围合适')
                rangeLengthOK = true;
            }
        } else if (this.gateDirection == GateDirection.Right || this.gateDirection == GateDirection.LEft) {
            if (this.max1.z <= rowAndColMin && this.max2.z >= rowAndColMax) {
                console.log('范围合适')
                rangeLengthOK = true;
            }
        }



        let colorOK = false;
        if (otherNode.getComponent(Block).modelColor == this.modelColor) {
            console.log('颜色相同了')
            colorOK = true;
        }

        let whetherBlockOK = false;
        if (new LBlockADsorptionEffect(
            otherNode.getWorldPosition(),
            this.gridController.getTileList(),
            this.gridController.getTopRightPos(),
        ).calcWhetherBlock(this.gateDirection, otherNode.getComponent(Block).blockDirection)) {
            console.log('没有被阻挡')
            whetherBlockOK = true;
        }
        if (rangeLengthOK && colorOK && whetherBlockOK) {
            console.log('可以被消除了')
            this.hanleElimination(otherNode.getComponent(Block));
        }
        //判断是否有阻挡

    }
    hanleElimination(block: Block) {
        let blockNode = block.node;
        let blockWordPos = blockNode.getWorldPosition();
        block.setMatertialClipPlane(this.gateDirection);
        blockNode.getComponent(RigidBody).enabled = false;
        blockNode.getComponent(BoxCollider).enabled = false;
        let { width, height } = block.getBlockWH();
        const target = blockWordPos.clone();
        if (this.gateDirection == GateDirection.TOP) {
            target.z += height;
        } else if (this.gateDirection == GateDirection.LEft) {
            target.x += width;
        } else if (this.gateDirection == GateDirection.Right) {
            target.x -= width;
        } else if (this.gateDirection == GateDirection.Bottom) {
            target.z -= height;
        }
        tween(blockNode)
            .to(1, { worldPosition: target })
            .call(() => {
                ChessboardState.clearValue(blockNode.name);
                blockNode.destroy();
            })
            .start();
    }
    onCollisionExit() {

    }
    //计算门的最大范围值
    calcMaxRang() {
        console.log(this.gateDirection, 'this.gateDirection')
        switch (this.gateDirection) {
            case GateDirection.TOP:
                return {
                    max1: this.horizontalCalcTopGateRigthBottomPos(),
                    max2: this.horizontalCalcTopGateLeftBottomPos()
                }
            case GateDirection.LEft:
                return {
                    max1: this.verticalCcalcuLateRigthTopPos(),
                    max2: this.verticalCcalcuLateRigthBottomPos()
                }
            case GateDirection.Right:
                return {
                    max1: this.verticalCalcRightGateRightTopPos(),
                    max2: this.verticalCalcRightGateRightBottomPos()
                }
            case GateDirection.Bottom:
                return {
                    max1: this.horizontalCalcBottomGateRightTop(),
                    max2: this.horizontalCalcBottomGateLeftTop()
                }
            default:
                break;
        }
    }
    verticalCcalcuLateRigthBottomPos() {
        let gateWordPos = this.node.worldPosition;
        let rightTopPos = new Vec3(gateWordPos.x, 0, gateWordPos.z - this.gateLength / 2);
        let diff = new Vec3(rightTopPos.x - this.gridController.getTopRightPos().x, 0, rightTopPos.z - this.gridController.getTopRightPos().z);
        // console.log(diff.x / 2, diff.z / 2)
        return {
            x: Math.floor(Math.abs(diff.x / 2)),
            z: Math.floor(Math.abs(diff.z / 2))
        }
    }
    verticalCcalcuLateRigthTopPos() {
        let gateWordPos = this.node.worldPosition;
        let rightTopPos = new Vec3(gateWordPos.x, 0, gateWordPos.z + this.gateLength / 2);
        let diff = new Vec3(rightTopPos.x - this.gridController.getTopRightPos().x, 0, rightTopPos.z - this.gridController.getTopRightPos().z);
        // console.log(diff.x / 2, diff.z / 2)
        return {
            x: Math.floor(Math.abs(diff.x / 2)),
            z: Math.floor(Math.abs(diff.z / 2))
        }
    }
    horizontalCalcTopGateRigthBottomPos() {
        let gateWordPos = this.node.worldPosition;
        let rigthBottomPos = new Vec3(gateWordPos.x - (this.gateLength / 2) - 1, 0, gateWordPos.z - 1);
        let diff = new Vec3(rigthBottomPos.x - this.gridController.getTopRightPos().x, 0, rigthBottomPos.z - this.gridController.getTopRightPos().z);
        return {
            x: Math.floor(Math.abs(diff.x / 2)),
            z: Math.floor(Math.abs(diff.z / 2))
        }
    }
    horizontalCalcTopGateLeftBottomPos() {
        let gateWordPos = this.node.worldPosition;
        let leftBottomPos = new Vec3(gateWordPos.x + this.gateLength - 1, 0, gateWordPos.z - 1);
        let diff = new Vec3(leftBottomPos.x - this.gridController.getTopRightPos().x, 0, leftBottomPos.z - this.gridController.getTopRightPos().z);
        return {
            x: Math.floor(Math.abs(diff.x / 2)),
            z: Math.floor(Math.abs(diff.z / 2))
        }
    }
    verticalCalcRightGateRightTopPos() {
        let gateWordPos = this.node.worldPosition;
        let rightTopPos = new Vec3(gateWordPos.x, 0, this.gateLength);
        let diff = new Vec3(rightTopPos.x - this.gridController.getTopRightPos().x, 0, rightTopPos.z - this.gridController.getTopRightPos().z);
        return {
            x: Math.floor(Math.abs(diff.x / 2)),
            z: Math.floor(Math.abs(diff.z / 2))
        }
    }
    verticalCalcRightGateRightBottomPos() {
        let gateWordPos = this.node.worldPosition;
        let rightBottomPos = new Vec3(gateWordPos.x, 0, -this.gateLength);
        let diff = new Vec3(rightBottomPos.x - this.gridController.getTopRightPos().x, 0, rightBottomPos.z - this.gridController.getTopRightPos().z);
        return {
            x: Math.floor(Math.abs(diff.x / 2)),
            z: Math.floor(Math.abs(diff.z / 2) - 1)
        }
    }
    horizontalCalcBottomGateRightTop() {
        let gateWordPos = this.node.worldPosition;
        let rightTopPos = new Vec3(gateWordPos.x - this.gateLength + 0.2, 0, gateWordPos.z);
        let diff = new Vec3(rightTopPos.x - this.gridController.getTopRightPos().x, 0, rightTopPos.z - this.gridController.getTopRightPos().z);
        return {
            x: Math.floor(Math.abs(diff.x / 2)),
            z: Math.floor(Math.abs(diff.z / 2))
        }
    }
    horizontalCalcBottomGateLeftTop() {
        let gateWordPos = this.node.worldPosition;
        let leftTopPos = new Vec3(gateWordPos.x + this.gateLength - 0.2, 0, gateWordPos.z);
        let diff = new Vec3(leftTopPos.x - this.gridController.getTopRightPos().x, 0, leftTopPos.z - this.gridController.getTopRightPos().z);
        return {
            x: Math.floor(Math.abs(diff.x / 2)),
            z: Math.floor(Math.abs(diff.z / 2))
        }
    }
    upDateGateModel() {
        this.Visual.setScale(this.gateLength, 1, 1);
        this.node.getComponent(BoxCollider).size.set(this.gateLength * 2, 1.1, 9.1)
    }
    updateGateDirection(dir: GateDirection) {
        switch (dir) {
            case GateDirection.TOP:
                this.node.setRotationFromEuler(new Vec3(88, 0, 0))
                break;
            case GateDirection.Bottom:
                this.node.setRotationFromEuler(new Vec3(88, -180, 0))
                break;
            case GateDirection.LEft:
                this.node.setRotationFromEuler(new Vec3(88, 90, 0))
                break;
            case GateDirection.Right:
                this.node.setRotationFromEuler(new Vec3(88, -90, 0))
            default:
                break;
        }
    }
    update(deltaTime: number) {

    }
}


